/**
* \file DGImage.hpp
*
* \brief This file defines the class for reading and writing of PNM ASCII images.
* \author Shekhar S. Chandra, 2008
*
* This file is part of DGV Library.
*
* DGV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DGV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DGV.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DGIMAGE_H
#define DGIMAGE_H

#include <string>
#include <fstream>

#include "DGVGlobal.h"

using namespace std;

///Globals
const int lineLength = 256;

/**
 \class DGImage
 \brief Wraps the reading and writing of PNM ASCII images.
*/
template<typename type>
class DGV_TEMPLATEDLL DGImage
{
public:
    DGImage();
    virtual ~DGImage();

    /**
        \fn
        \brief
    */
    bool isPNMBinaryFormat(string filename);

    /**
        \fn readPNM(string filename, Array<type,2> &data, int &greyMax)
        \brief Reads ASCII PNM (Portable aNy Map) Image files. Returns true if successful.
        Formats of PNM supported are *.pgm, *.ppm (mono) and *.pbm.
    */
    bool readPNM(string filename, Array<type,2> &data, int &greyMax);
    /**
        \fn writePNM(Array<type,2> &data, const int greyMax, string filename)
        \brief Writes ASCII PNM (Portable aNy Map) Image files. Returns true if successful.
        Formats of PNM supported are *.pgm, *.ppm (mono) and *.pbm.
    */
    bool writePNM(Array<type,2> &data, const int greyMax, string filename);
protected:

};

template<typename type>
DGImage<type>::DGImage()
{
    //ctor
}

template<typename type>
DGImage<type>::~DGImage()
{
    //dtor
}

template<typename type>
bool DGImage<type>::isPNMBinaryFormat(string filename)
{
    ifstream inFile(filename.c_str());
    char c;
    string magic;

    if(inFile.fail())
        return false;

    do
    {
        inFile >> c;
        if (c == '\0')
        {
            // Bad file.
            inFile.close();
            return false;
        }
    }
    while (c != 'P');
    magic += c;
    inFile >> c; ///Get File Type magic number
    magic += c;

    //cerr << "PNM Magic Number: " << magic << endl;
    if ( magic == "P4" || magic == "P5" || magic == "P6" )
        return true;
    else
        return false;
}

template<typename type>
bool DGImage<type>::readPNM(string filename, Array<type,2> &data, int &greyMax)
{
    char portable = 0, fileType, comment[lineLength];
    int width = 0, height = 0;
    ifstream inFile;

    inFile.open(filename.c_str()); //!< Open File.

    if(inFile.fail())
        return false;

    ///Read PGM Header
    ///Read Filetype and File comment
    while(portable != 'P')
        inFile >> portable;
	inFile >> fileType; ///Read File Type (1-3 = ASCII where 1 is 1-bit and 2 is plain, 4-6 = Binary)
	cerr << "File Type: " << portable << fileType << endl;
	while(portable != '#')
        inFile >> portable;
	inFile.getline(comment,lineLength); ///Get comment
	cerr << "File Info: " << comment << endl;

    ///Read Image Characteristics
    inFile >> width;
    inFile >> height;
    if(fileType != '1')
        inFile >> greyMax;
    else
        greyMax = 1;
	printf("File Size: %dx%d, Grey Scale Max: %d\n",width, height, greyMax);

    ///Allocate Memory for Image appropriately
    data.resizeAndPreserve(height,width);

    ///Read Data according to size and type provided in header
    if((fileType == '2') || (fileType == '1'))
	{
		for(int j = 0; j < height; j ++)
            for(int k = 0; k < width; k ++)
                inFile >> data(j,k);
	}
    else if(fileType == '3')
	{
		for(int j = 0; j < height; j ++)
            for(int k = 0; k < width; k ++)
			{
                inFile >> data(j,k); ///Black & White PPM
                inFile >> data(j,k);
                inFile >> data(j,k);
            }
	}

	inFile.close(); //!< Close File.

    return true;
}

template<typename type>
bool DGImage<type>::writePNM(Array<type,2> &data, const int greyMax, string filename)
{
    ofstream outFile;

    outFile.open(filename.c_str());
    if(outFile.fail())
        return false;

    outFile << "P2\n# Generated PGM by DGV.\n";
    outFile << data.cols() << " " << data.rows() << endl << greyMax << endl;

    for(int j = 0; j < data.rows(); j ++)
    {
        for(int k = 0; k < data.cols(); k ++)
            outFile << data(j,k) << " ";
        outFile << endl;
    }

    outFile.close();
    return true;
}

#endif // DGIMAGE_H
